HI!上一篇我們提到了可以用Props
可以從外部傳進值,就像以下做法,今天進入正文的也太突然了XD:
//建立一個NowTime組件類別顯示目前時間
class NowTime extends React.Component {
render(){
//讀取props中取出time的值
return <h1>現在時間是{this.props.time}</h1>
}
}
//使用該類別做出一個實體,並將目前的時間傳入time中
ReactDOM.render(<NowTime time={new Date().toLocaleTimeString()} />
,document.getElementById('root'))
如果是上面的用法,雖然使用時會具有彈性,但是每次只要使用該組件,就必須在要再把值傳入time
中,反過來想既然那個組件只顯示時間,為何不將time
直接設定在組件當中,這樣不僅在使用時可以更方便,也能夠減少資料錯誤的機會,對吧!為了完成這件事我們要介紹組件的第二位成員State
。
state
屬性叫做狀態,也就是在組件中自身不會被修改的屬性,在class
中可以通過constructor
來設定state
,例如:
class NowTime extends React.Component {
//使用類別中的constructor建構子,參數中傳入props是必要的
constructor(props){
//super呼叫上一層類別也就是React.Component內的props屬性
super(props)
/*設定該類別的屬性,this就是指定到使用NowTime建構出來的物件
這裡針對那個物件建立一個state的物件屬性,並在裡面設定該類別的值*/
this.state = {time : new Date().toLocaleTimeString()}
}
render(){
//使用this(呼叫該建構器的物件)中的state(剛剛建立的物件屬性)內的time
return <h1>現在時間是{this.state.time}</h1>
}
}
//直接使用該類別做出一個實體,不再另外設定傳入值
ReactDOM.render(<NowTime />,document.getElementById('root'))
會顯示當組件被建立的時間。
這麼一來雖然在建構一個組件類別的時候需要打的程式比較多,但是在使用時就能直接呼叫類別,不必再每次呼叫類別的時候都重新設定Props
,所以如果有固定不變的東西,不妨就放進去裡面吧!
這是文章中第二個要提到的部分:生命週期,在這個生命週期中,有兩個函式分別在建構完組件和組件結束(被移除)的時候執行,以下來認識他們吧:
componentDidMount()
在class
類別裡設定componentDidMount()
方法的話,會在該class
建構完組件的時候被執行,上方的例子使用了setInterval
不斷進行重新建構,再放入畫面上的方式來刷新時間,而上方學習到的state
屬性,讓我們知道可以在組件內部設定自有的資料,所以我們就可以利用改變state
的值來讓畫面刷新,就不必在class
外的地方操作組件的行為:
class NowTime extends React.Component {
constructor(props){
super(props)
this.state={time : new Date().toLocaleTimeString()}
}
//加入組件建構完成後執行的事件
componentDidMount(){
/*在建構完成後,每秒都去刷新this.state.time的值
(1)先去宣告一個更新state內容的function
(2)每秒去執行一次該function刷新*/
const upTime = () =>{
//這裡面的setState()能夠重新設定state的值
this.setState({time : new Date().toLocaleTimeString()})
}
setInterval(upTime,1000)
}
render(){
return <h1>現在時間是{this.state.time}</h1>
}
}
ReactDOM.render(<NowTime />,document.getElementById('root'))
GitHub程式碼連結
GitPage連結
透過上面調用componentDidMount()
的方式,讓刷新畫面這個動作得以在組件內設置完成。不過上面是拿componentDidMount()
來設定刷新頁面的function
,其實只要是想在組件產生後先執行的動作,通通都可以寫在componentDidMount()
裡面,所以記得哦!這是組件建構完成後接著會執行的地方。
setState()
修改狀態值再接著介紹下一位之前先認識一位新朋友,相信在上方的範例程式碼中,大家都有看到一個新的函式setState()
,在組件中可以利用該函式來修改組件的state
,就像上方做的那樣,不過他有幾個點是需要注意的:
setState()
來修改狀態值:
setState({time : new Date().toLocaleTimeString()})
以下方法是錯誤且無效的:
this.state.time = new Date().toLocaleTimeString()
setState()
並不是用覆蓋的方式,而是更新:state
有兩個值:
this.state = ({name:'GQSM',age:25})
當我只更新name
時age
是不會變的,所以不必每次都重新給一堆資料
setState({name:'GQSM_Ver2.0'})
state
和props
中的資料更新是異步的,所以當setState
需要同步props
的資料時,必須傳入props
做使用,並回傳計算完後的結果物件給setState
:
//傳入目前的state及props進行同步處理
setState((state,props)=>({age : state.age + props.year}))
以下可能會抓到錯的props
資料
setState({age : this.state.age + this.props.year})
以上三點中,最後一個也許會比較難理解,雖然目前只是用理論闡述需要注意這件事情,但是當之後的日子中有提到的話,會再提一次這個部分,讓大家也能夠在實作中明白這點,啊如果有大大了解的話再麻煩留言提點我,我會再把這裡補充的清楚一些!謝謝!
componentDidUpdate()
緊接著出現的是也還不是結束時執行的函式XD,上方我們學會利用了setState()
修改state
的值,而componentDidUpdate()
正是在state
被修改時會執行的函式,算是生命週期中的過程!那我們來看看他如何使用!
class NowTime extends React.Component {
constructor(props){
super(props)
this.state={time : new Date().toLocaleTimeString()}
}
componentDidMount(){
const upTime = () =>{
this.setState({time : new Date().toLocaleTimeString()})
}
setInterval(upTime,1000)
}
//加入state被修改時會執行的函式
componentDidUpdate(){
//執行內容
console.log('時間一分一秒在跑...')
}
render(){
return <h1>現在時間是{this.state.time}</h1>
}
}
ReactDOM.render(<NowTime />,document.getElementById('root'))
當state
中的值被修改就會執行:
componentWillUnmount()
既然有開始,那就會有結束的時候,當組件被移除需要執行事情的時候就放心交給componentWillUnmount()
吧!在這裡我們先簡單的在componentWillUnmount()
中記錄一下被組件移除的時間點:
class NowTime extends React.Component{
constructor(props){
super(props)
this.state = {time : new Date().toLocaleTimeString()}
}
componentDidMount(){
const upTime = () =>{
this.setState({time : new Date().toLocaleTimeString()})
}
setInterval(upTime,1000)
}
//組件結束時會執行的事件
componentWillUnmount(){
//這裡記錄移除掉的時間
console.log(`移除組件的時間為:${this.state.time}`)
}
render(){
return <h1>現在時間是:{this.state.time}</h1>
}
}
ReactDOM.render(<NowTime />,document.getElementById('root'))
好的,上方已經設定好移除組件時該執行的動作,可是我們該怎麼移除掉組件呢?沒問題!想到操作組件就會想到ReactDOM
,只要是控制組件就交給他吧!
ReactDOM
中有個方法unmountComponentAtNode(Element)
能夠移除在Element
中的組件,移除完後會回傳true
,但是如果移除失敗或是指定的Element
中沒有組件,那就會回傳false
,以下把它加進去做測試,看組件消失時會不會執行componentWillUnmount()
:
class NowTime extends React.Component{
constructor(props){
super(props)
this.state = {time : new Date().toLocaleTimeString()}
}
componentDidMount(){
const upTime = () =>{
this.setState({time : new Date().toLocaleTimeString()})
}
setInterval(upTime,1000)
}
componentWillUnmount(){
console.log(`移除組件的時間為:${this.state.time}`)
}
render(){
return <h1>現在時間是:{this.state.time}</h1>
}
}
ReactDOM.render(<NowTime />,document.getElementById('root'))
//宣告一個function,來移除document.getElementById('root')中的組件
const removeComponent = () =>{
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
//延遲五秒後執行移除
setTimeout(removeComponent,5000)
執行結果上方的英字串是我亂打的:
5秒後消失並記錄時間:
經過本編文章介紹的componentDidMount()
和componentWillUnmount()
可以暸解到上方NowTime
組件的生命週期大概是這樣子的:
constructor
中初始化組件內部的資料。render()
在網頁上輸出組件內容。componentDidMount()
進行一次調用。state
值被修改時執行componentDidUpdate()
。componentWillUnmount()
的內容一次。當然,每次去呼叫的組件都是獨一無二的,所以會有自己的生命週期在,不會因為他是從同一個class
中建構出來而共用一個生命週期。
這是鐵人賽的第五篇,感覺還沒有找到應該有的節奏,其實我應該更放寬心去面對鐵人賽的,對吧!哈哈!
那今天的文章到這裡,感謝各位大大的觀看!如果文章中有任何問題,或是沒有解釋清楚的地方,還麻煩留言告訴我,謝謝大家
參考文章:
加油!一起學習!!
我覺得自己越寫越艱困了
加油啊!同是React
好夥伴,
遇到問題可以互相討論XD
一起衝到最後